import os
import gtk, gtk.gdk, gobject

gtk.gdk.threads_init()

import gtkhtml2
import gtkhtml3
from kiwi.ui.objectlist import Column, ObjectList
from kiwi.ui.widgets.combo import ProxyComboBox
from kiwi.ui.delegates import GladeDelegate
from kiwi.ui.dialogs import error
from kiwi import ValueUnset

from client import BlogClient

from threading import Thread

class ThreadRunner(object):

    def __init__(self, progress_bar, call, callback, errback,
                 run_text='', fin_text='', *args, **kw):
        self._progress_bar = progress_bar
        self._call = call
        self._callback = callback
        self._errback = errback
        self._pulsing = True
        self._args = args
        self._kw = kw
        self._run_text = run_text
        self._fin_text = fin_text
        gobject.timeout_add(500, self.pulse)
        t = Thread(target=self.run)
        t.start()

    def run(self):
        def ini(): 
            self._progress_bar.set_text(self._run_text)
        gobject.idle_add(ini)
        try:
            self._call(*self._args, **self._kw)
            def _cb():
                if self._callback is not None:
                    self._callback()
                self._progress_bar.set_text(self._fin_text)
            gobject.idle_add(_cb)
        except Exception, e:
            def err():
                self._progress_bar.set_text(str(e))
                if self._errback is not None:
                    self._errback()
            gobject.idle_add(err)
        self._pulsing = False
        def _fin():
            self._progress_bar.set_fraction(1.0)
        gobject.timeout_add(500, _fin)

    def pulse(self):
        gobject.idle_add(self._progress_bar.pulse)
        return self._pulsing


        

class HTMLView(gtk.ScrolledWindow):

    def __init__(self):
        super(HTMLView, self).__init__()
        self._view = gtkhtml2.View()
        self.add(self._view)
        self._document = gtkhtml2.Document()
        self._view.set_document(self._document)
    
    def load_html(self, html):
        self.clear()
        self._document.open_stream('text/html')
        self._document.write_stream(html)
        self._document.close_stream()

    def clear(self):
        self._document.clear()


class GladeDialogDelegate(GladeDelegate):

    """
    Dialog Delegate - A bit shitty

    Expects the glade file to have an ok_button and a cancel_button
    """

    gladefile = None

    def __init__(self, parent=None, delete_handler=None, gladefile=None):
        if not delete_handler:
            delete_handler = self.close
        self.setup_keyactions()
        gladefile = gladefile or self.gladefile
        GladeDelegate.__init__(self, gladefile=self.gladefile,
                               delete_handler=delete_handler,
                               keyactions=self.keyactions)
        self.parent = parent
        self.retval = None

    def close(self, *args):
        self.get_toplevel().hide()

    def destroy(self):
        self.get_toplevel().destroy()

    def run(self):
        # If parent is a BaseView, use GTK+ calls to get the toplevel
        # window. This is a bit of a hack :-/
        if isinstance(self.parent, GladeDelegate):
            parent = self.parent.get_toplevel().get_toplevel()
            if parent:
                self.get_toplevel().set_transient_for(parent)
                self.get_toplevel().set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.get_toplevel().run()
        self.destroy()
        return self.retval

    def setup_keyactions(self):
        self.keyactions = {gtk.keysyms.Escape: self.cancel}

    def confirm(self, *args):
        self.retval = True
        self.close()

    def cancel(self, *args):
        self.retval = False
        self.close()
    #
    # Kiwi handlers
    #

    def on_ok_button__clicked(self, button):
        self.confirm()

    def on_cancel_button__clicked(self, button):
        self.cancel()




class LoginDialog(GladeDialogDelegate):

    gladefile = 'login_dialog'

    def __init__(self, *args, **kw):
        GladeDialogDelegate.__init__(self, *args, **kw)

    def confirm(self):
        self.retval = (self.username_entry.get_text(),
                       self.pw_entry.get_text(),
                       self.save_check.get_active())
        self.close()

    def _reset_entries(self):
        self.username_entry.set_text('')
        self.pw_entry.set_text('')
        self.username_entry.grab_focus()

    def on_username_entry__activate(self, entry):
        self.pw_entry.grab_focus()

    def on_pw_entry__activate(self, entry):
        self.ok_button.clicked()

ITEM_COLUMNS = [Column('title')]

class BlogConfig(object):

    def __init__(self):
        self._username = ''
        self._password = ''
        self._file = os.path.expanduser('~/.gblogger')
        self._load()

    def _load(self):
        if os.path.exists(self._file):
            f = open(self._file, 'r')
            try:
                self._username, self._password = f.read().split('\n')
            except:
                pass
            f.close()

    def save(self):
            f = open(self._file, 'w')
            f.write('\n'.join([self._username, self._password]))
            f.close()

    def get_credentials(self):
        return self._username, self._password

    def set_credentials(self, username, password):
        self._username, self._password = username, password


class BlogDelegate(GladeDelegate):

    gladefile = 'main_window'

    def __init__(self, *args, **kw):
        self._client = BlogClient()
        GladeDelegate.__init__(self, delete_handler=self.on_delete_event, *args, **kw)
        self._config = BlogConfig()
        self.create_ui()
        self.reset_ui()
        self.connect()

    def on_delete_event(self, window, event):
        self.hide_and_quit()

    def create_ui(self):
        self.html_view = HTMLView()
        self.html_fr.add(self.html_view)
        self.html_fr.show_all()
        self.itemlist.set_columns(ITEM_COLUMNS)
        self.itemlist.set_sensitive(False)
        self.bloglist.set_sensitive(False)
        self.act_new.set_sensitive(False)
        self.act_edit.set_sensitive(False)
        self.act_refresh.set_sensitive(False)


    def reset_ui(self):
        blogs = self._client.get_blogs()
        if len(blogs):
            self.bloglist.prefill([(b.title, b) for b in blogs])
            self.bloglist.set_sensitive(len(blogs) > 1)
            self.act_new.set_sensitive(True)

    def load_client(self):
        self.act_refresh.set_sensitive(False)
        ThreadRunner(self.progressbar, self._client.load, self.client_loaded,
            None, 'Downloading Blog Data', 'Blog Data Downloaded')

    def client_loaded(self):
        self.reset_ui()
        self.act_refresh.set_sensitive(True)

    def edit(self, item):
        content = gtkhtml3.HTMLEditor(self.get_toplevel()).run(item.title, item.content)
        if content is not None:
            title, data = content
            data = self._get_inner_body(data)
            def edited():
                item.title = title
                item.content = data
                self.itemlist.refresh(item)
                self.itemlist.select(item)
            ThreadRunner(self.progressbar, item.edit, edited, None,
                'Sending Edited Blog Item "%s"' % item.title,
                'Sent Edited Blog Item "%s"' % title,
                title, data
            )


    def on_bloglist__content_changed(self, cb):
        item = cb.read()
        self.itemlist.clear()
        if item not in [ValueUnset, None]:
            self.itemlist.extend(item.get_blog_items())
            self.itemlist.set_sensitive(True)
        else:
            self.itemlist.set_sensitive(False)

    def on_itemlist__selection_changed(self, ol, item):
        if item is None:
            self.act_edit.set_sensitive(False)
            self.html_view.clear()
        else:
            self.act_edit.set_sensitive(True)
            self.html_view.load_html(item.content)

    def on_itemlist__double_click(self, ol, item):
        self.edit(item)

    def on_act_connect__activate(self, action):
        self.connect()

    def connect(self):
        if '' in self._config.get_credentials():
            l = LoginDialog()
            username, password, save = l.run()
            self._config.set_credentials(username, password)
            if save:
                self._config.save()
        ThreadRunner(self.progressbar, self._client.connect, self.connected,
                     self.not_connected,
                     'Connecting to Google Accounts', 'Connected',
                     *self._config.get_credentials())

    def not_connected(self):
        self._config.set_credentials('', '')
        self._config.save()

    def connected(self):
        self.act_refresh.set_sensitive(True)
        self.act_connect.set_sensitive(False)
        self.load_client()

    def on_act_new__activate(self, action):
        blog = self.bloglist.read()
        content = gtkhtml3.HTMLEditor(self.get_toplevel()).run()
        if content is not None:
            title, data = content
            data = self._get_inner_body(data)
            ThreadRunner(self.progressbar, blog.post, self.new_posted, None,
                'Sending Edited Blog Item "%s"' % title,
                'Sent Edited Blog Item "%s"' % title,
                title, data
            )

    def new_posted(self):
        self.load_client()

    def on_act_edit__activate(self, action):
        item = self.itemlist.get_selected()
        self.edit(item)

    def on_act_refresh__activate(self, action):
        self.bloglist.prefill([])
        self.load_client()

    def _get_inner_body(self, content):
        cnt = content.split('<BODY>')[-1].split('</BODY>')[0]
        return cnt

def main():
    gtk.gdk.threads_enter()
    b = BlogDelegate()
    b.show_and_loop()
    gtk.gdk.threads_leave()



